using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Security.AccessControl;
using System.IO;
using log4net;

namespace CodeWork.Library
{
    public sealed class FileAccessUtility
    {
        /// <summary>
        /// Private constructor to restrict instance creation
        /// </summary>
        private FileAccessUtility() { }

        /// <summary>
        /// Creates a file in the path location with the provided string content.
        /// The path includes the file name also and is relative to the root of
        /// the website
        /// </summary>
        /// <param name="fullRelativePath">The path where to create the file</param>
        /// <param name="content">string content of the file</param>
        /// <returns>True if file is successfuly created, false otherwise.</returns>
        public static bool CreateFile(string fullRelativePath, string content)
        {
            try
            {
                bool result = false;
                // If the path is present
                if (!string.IsNullOrEmpty(fullRelativePath))
                {
                    // Resolve the relative path
                    string fileName = HttpContext.Current.Server.MapPath(fullRelativePath);

                    // Create the file
                    using (FileStream fileStream = File.Create(fileName))
                    {
                        // If the file is writable
                        if (fileStream.CanWrite)
                        {
                            // Using the unicode format and counting how many bytes the content
                            // will take in that format
                            UnicodeEncoding uniEncoding = new UnicodeEncoding();
                            // Writing the content in the file
                            fileStream.Write(uniEncoding.GetBytes(content), 0, uniEncoding.GetByteCount(content));
                            fileStream.Close();
                            result = true;
                        }
                    }
                }
                return result;
            }
            catch (Exception ex)
            {
                // Setting log information about the exception
                StringBuilder logText = new StringBuilder("Create file caused server error: Parameters( ");
                logText = logText.Append("fullRelativePath -> ").Append(fullRelativePath);
                logText = logText.Append("content -> ").Append(content);
                logText = logText.Append(" )");

                // Write the log into handled exception list
                ILog log = LogHelper.GetHandledFileLogger("FileAccessUtility");
                if (log.IsErrorEnabled)
                    log.Error(logText.ToString(), ex);

                // return failure
                return false;
            }
        }

        /// <summary>
        /// Deletes a file in the path location. The path includes the file 
        /// name also and is relative to the root of the website
        /// </summary>
        /// <param name="fullRelativePath">The path where to create the file</param>
        /// <returns>True if file is successfuly deleted, false otherwise.</returns>
        public static bool DeleteFile(string fullRelativePath)
        {
            try
            {
                // Resolve the relative path
                string fileName = HttpContext.Current.Server.MapPath(fullRelativePath);
                // Adding file security permission for deletion
                AddFileSecurity(fileName, System.Security.Principal.WindowsIdentity.GetCurrent().Name,
                  FileSystemRights.Delete, AccessControlType.Allow);
                // Deleting the file
                File.Delete(fileName);
                return true;
            }
            catch (Exception ex)
            {
                // Setting log information about the exception
                StringBuilder logText = new StringBuilder("Delete file caused server error: Parameters( ");
                logText = logText.Append("fullRelativePath -> ").Append(fullRelativePath);
                logText = logText.Append(" )");

                // Write the log into handled exception list
                ILog log = LogHelper.GetHandledFileLogger("FileAccessUtility");
                if (log.IsErrorEnabled)
                    log.Error(logText.ToString(), ex);

                // return failure
                return false;
            }
        }

        /// <summary>
        /// Creates a folder in the path location. The path includes the 
        /// file name also and is relative to the root of the website.
        /// </summary>
        /// <param name="fullRelativePath">The path where to create the file</param>
        /// <returns>True if folder is successfuly created, false otherwise.</returns>
        public static bool CreateFolder(string fullRelativePath)
        {
            try
            {
                // Resolve the relative path
                string folderName = HttpContext.Current.Server.MapPath(fullRelativePath);
                // Creating the directory
                DirectoryInfo directoryInfo = Directory.CreateDirectory(folderName);
                return true;
            }
            catch (Exception ex)
            {
                // Setting log information about the exception
                StringBuilder logText = new StringBuilder("Create folder caused server error: Parameters( ");
                logText = logText.Append("fullRelativePath -> ").Append(fullRelativePath);
                logText = logText.Append(" )");

                // Write the log into handled exception list
                ILog log = LogHelper.GetHandledFileLogger("FileAccessUtility");
                if (log.IsErrorEnabled)
                    log.Error(logText.ToString(), ex);

                // return failure
                return false;
            }
        }

        /// <summary>
        /// Deletes a folder in the path location including child content. The path 
        /// includes the file name also and is relative to the root of the website
        /// </summary>
        /// <param name="fullRelativePath">The path where to create the file</param>
        /// <returns>True if folder is successfuly deleted, false otherwise.</returns>
        public static bool DeleteFolder(string fullRelativePath)
        {
            try
            {
                // Resolve the relative path
                string folderName = HttpContext.Current.Server.MapPath(fullRelativePath);
                // If the directory is found
                DirectoryInfo directoryInfo = new DirectoryInfo(folderName);
                if (directoryInfo.Exists)
                {
                    // Adding folder security permission for deletion
                    AddDirectorySecurity(folderName, System.Security.Principal.WindowsIdentity.GetCurrent().Name,
                      FileSystemRights.Delete, AccessControlType.Allow);
                    // Deleting the folder including all child content
                    Directory.Delete(folderName, true);
                }
                return true;
            }
            catch (Exception ex)
            {
                // Setting log information about the exception
                StringBuilder logText = new StringBuilder("Delete folder caused server error: Parameters( ");
                logText = logText.Append("fullRelativePath -> ").Append(fullRelativePath);
                logText = logText.Append(" )");

                // Write the log into handled exception list
                ILog log = LogHelper.GetHandledFileLogger("FileAccessUtility");
                if (log.IsErrorEnabled)
                    log.Error(logText.ToString(), ex);

                // return failure
                return false;
            }
        }

        // Adds an ACL entry on the specified file for the specified account.
        public static bool AddFileSecurity(string fileName, string account,
            FileSystemRights rights, AccessControlType controlType)
        {
            try
            {
                // Get a FileSecurity object that represents the
                // current security settings.
                FileSecurity fSecurity = File.GetAccessControl(fileName);

                // Add the FileSystemAccessRule to the security settings.
                fSecurity.AddAccessRule(new FileSystemAccessRule(account, rights, controlType));

                // Set the new access settings.
                File.SetAccessControl(fileName, fSecurity);

                return true;
            }
            catch (Exception ex)
            {
                // Setting log information about the exception
                StringBuilder logText = new StringBuilder("Add file security caused server error: Parameters( ");
                logText = logText.Append("fileName -> ").Append(fileName);
                logText = logText.Append("account -> ").Append(account);
                logText = logText.Append("rights -> ").Append(rights.ToString());
                logText = logText.Append("controlType -> ").Append(controlType.ToString());
                logText = logText.Append(" )");

                // Write the log into handled exception list
                ILog log = LogHelper.GetHandledFileLogger("FileAccessUtility");
                if (log.IsErrorEnabled)
                    log.Error(logText.ToString(), ex);

                // return failure
                return false;
            }
        }

        // Removes an ACL entry on the specified file for the specified account.
        public static bool RemoveFileSecurity(string fileName, string account,
            FileSystemRights rights, AccessControlType controlType)
        {
            try
            {
                // Get a FileSecurity object that represents the
                // current security settings.
                FileSecurity fSecurity = File.GetAccessControl(fileName);

                // Remove the FileSystemAccessRule from the security settings.
                fSecurity.RemoveAccessRule(new FileSystemAccessRule(account, rights, controlType));

                // Set the new access settings.
                File.SetAccessControl(fileName, fSecurity);

                return true;
            }
            catch (Exception ex)
            {
                // Setting log information about the exception
                StringBuilder logText = new StringBuilder("Remove file security caused server error: Parameters( ");
                logText = logText.Append("fileName -> ").Append(fileName);
                logText = logText.Append("account -> ").Append(account);
                logText = logText.Append("rights -> ").Append(rights.ToString());
                logText = logText.Append("controlType -> ").Append(controlType.ToString());
                logText = logText.Append(" )");

                // Write the log into handled exception list
                ILog log = LogHelper.GetHandledFileLogger("FileAccessUtility");
                if (log.IsErrorEnabled)
                    log.Error(logText.ToString(), ex);

                // return failure
                return false;
            }
        }

        // Adds an ACL entry on the specified folder for the specified account.
        public static bool AddDirectorySecurity(string folderName, string account,
            FileSystemRights rights, AccessControlType controlType)
        {
            try
            {
                // Get a DirectorySecurity object that represents the
                // current security settings.
                DirectorySecurity dSecurity = Directory.GetAccessControl(folderName);

                // Add the FileSystemAccessRule to the security settings.
                dSecurity.AddAccessRule(new FileSystemAccessRule(account, rights, controlType));

                // Set the new access settings.
                Directory.SetAccessControl(folderName, dSecurity);

                return true;
            }
            catch (Exception ex)
            {
                // Setting log information about the exception
                StringBuilder logText = new StringBuilder("Add directory security caused server error: Parameters( ");
                logText = logText.Append("folderName -> ").Append(folderName);
                logText = logText.Append("account -> ").Append(account);
                logText = logText.Append("rights -> ").Append(rights.ToString());
                logText = logText.Append("controlType -> ").Append(controlType.ToString());
                logText = logText.Append(" )");

                // Write the log into handled exception list
                ILog log = LogHelper.GetHandledFileLogger("FileAccessUtility");
                if (log.IsErrorEnabled)
                    log.Error(logText.ToString(), ex);

                // return failure
                return false;
            }
        }

        // Removes an ACL entry on the specified folder for the specified account.
        public static bool RemoveDirectorySecurity(string folderName, string account,
            FileSystemRights rights, AccessControlType controlType)
        {
            try
            {
                // Get a DirectorySecurity object that represents the
                // current security settings.
                DirectorySecurity dSecurity = Directory.GetAccessControl(folderName);

                // Remove the FileSystemAccessRule from the security settings.
                dSecurity.RemoveAccessRule(new FileSystemAccessRule(account, rights, controlType));

                // Set the new access settings.
                Directory.SetAccessControl(folderName, dSecurity);

                return true;
            }
            catch (Exception ex)
            {
                // Setting log information about the exception
                StringBuilder logText = new StringBuilder("Remove directory security caused server error: Parameters( ");
                logText = logText.Append("folderName -> ").Append(folderName);
                logText = logText.Append("account -> ").Append(account);
                logText = logText.Append("rights -> ").Append(rights.ToString());
                logText = logText.Append("controlType -> ").Append(controlType.ToString());
                logText = logText.Append(" )");

                // Write the log into handled exception list
                ILog log = LogHelper.GetHandledFileLogger("FileAccessUtility");
                if (log.IsErrorEnabled)
                    log.Error(logText.ToString(), ex);

                // return failure
                return false;
            }
        }
    }
}
